<!DOCTYPE html>
<html class="has-navbar-fixed-top">
<head>
    <meta charset="utf-8">
<title>反射 - wanzixin</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.css">


<link href="/Study/Java/zh-cn/%E5%8F%8D%E5%B0%84/" rel="alternate" hreflang="en" />
    


<meta name="description" content="">





    <meta name="description" content="什么是反射？反射就是Reflection，Java的反射是指程序在运行期可以拿到一个对象的所有信息。反射是为了解决在运行期，对某个实例一无所知的情况下，如何调用其方法。">
<meta property="og:type" content="article">
<meta property="og:title" content="反射">
<meta property="og:url" content="https://wanzixin.github.io/Study/Java/zh-cn/%E5%8F%8D%E5%B0%84/index.html">
<meta property="og:site_name" content="wanzixin">
<meta property="og:description" content="什么是反射？反射就是Reflection，Java的反射是指程序在运行期可以拿到一个对象的所有信息。反射是为了解决在运行期，对某个实例一无所知的情况下，如何调用其方法。">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-04-29T01:43:58.000Z">
<meta property="article:modified_time" content="2021-05-30T14:25:21.220Z">
<meta property="article:author" content="wanzixin">
<meta name="twitter:card" content="summary">





<link rel="icon" href="/favicon.png">


<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Ovo|Source+Code+Pro">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">


<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/lightgallery/1.6.8/css/lightgallery.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/justifiedGallery/3.6.5/css/justifiedGallery.min.css">


<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-light.min.css">


<link rel="stylesheet" href="/css/style.css">


<script defer src="//use.fontawesome.com/releases/v5.0.8/js/all.js"></script>


    
    
    
    
    
    
    
    
    
    

    


<meta name="generator" content="Hexo 5.4.0"></head>
<body>
    
<nav class="navbar is-transparent is-fixed-top navbar-main" role="navigation" aria-label="main navigation">
    <div class="container">
        <div class="navbar-brand">
            <a class="navbar-item navbar-logo" href="/zh-cn">
                
                    
                    wanzixin
                    
                
            </a>
            <div class="navbar-burger">
                <span></span>
                <span></span>
                <span></span>
            </div>
        </div>
        
        <div class="navbar-menu navbar-start">
            
            <a class="navbar-item "
               href="/archives">Archives</a>
            
            <a class="navbar-item "
               href="/categories">Categories</a>
            
            <a class="navbar-item "
               href="/categories/Diary">Diary</a>
            
            <a class="navbar-item "
               href="/categories/Gallery">Gallery</a>
            
            <a class="navbar-item "
               href="/categories/Study">Study</a>
            
            <a class="navbar-item "
               href="/categories/Item">Item</a>
            
            <a class="navbar-item "
               href="/about">About</a>
            
        </div>
        
        <div class="navbar-menu navbar-end">
            
            <a class="navbar-item search" title="搜索" href="javascript:;">
                <i class="fas fa-search"></i>
            </a>
            
            
            <div class="navbar-item is-hoverable has-dropdown is-hidden-mobile is-hidden-tablet-only toc">
                <a class="navbar-item" title="目录">
                    <i class="fa fa-list"></i>
                </a>
                <div class="navbar-dropdown is-right">
                    
                    
                    
                    
                    <a class="navbar-item" href="#Class类">1&nbsp;&nbsp;<b>Class类</b></a>
                    
                    
                    
                    <a class="navbar-item" href="#动态加载">1.1&nbsp;&nbsp;动态加载</a>
                    
                    
                    <hr class="navbar-divider">
                    
                    
                    <a class="navbar-item" href="#访问字段">2&nbsp;&nbsp;<b>访问字段</b></a>
                    
                    
                    
                    <a class="navbar-item" href="#获取字段值">2.1&nbsp;&nbsp;获取字段值</a>
                    
                    
                    
                    <a class="navbar-item" href="#设置字段值">2.2&nbsp;&nbsp;设置字段值</a>
                    
                    
                    <hr class="navbar-divider">
                    
                    
                    <a class="navbar-item" href="#调用方法">3&nbsp;&nbsp;<b>调用方法</b></a>
                    
                    
                    
                    <a class="navbar-item" href="#调用方法-1">3.1&nbsp;&nbsp;调用方法</a>
                    
                    
                    
                    <a class="navbar-item" href="#调用静态方法">3.2&nbsp;&nbsp;调用静态方法</a>
                    
                    
                    
                    <a class="navbar-item" href="#调用非public方法">3.3&nbsp;&nbsp;调用非public方法</a>
                    
                    
                    
                    <a class="navbar-item" href="#多态">3.4&nbsp;&nbsp;多态</a>
                    
                    
                    <hr class="navbar-divider">
                    
                    
                    <a class="navbar-item" href="#调用构造方法">4&nbsp;&nbsp;<b>调用构造方法</b></a>
                    
                    
                    <hr class="navbar-divider">
                    
                    
                    <a class="navbar-item" href="#获取继承关系">5&nbsp;&nbsp;<b>获取继承关系</b></a>
                    
                    
                    
                    <a class="navbar-item" href="#获取interface">5.1&nbsp;&nbsp;获取interface</a>
                    
                    
                    
                    <a class="navbar-item" href="#继承关系">5.2&nbsp;&nbsp;继承关系</a>
                    
                    
                    
                    <a class="navbar-item" href="#动态代理">5.3&nbsp;&nbsp;动态代理</a>
                    
                </div>
            </div>
            
            
            <a class="navbar-item" title="GitHub" target="_blank" rel="noopener" href="https://github.com/wanzixin">
                
                <i class="fab fa-github"></i>
                
            </a>
               
            
        </div>
    </div>
</nav>

    <section class="section">
    <div class="container">
    <article class="article content gallery" itemscope itemprop="blogPost">
    <h1 class="article-title is-size-3 is-size-4-mobile" itemprop="name">
        
            反射
        
    </h1>
    <div class="article-meta columns is-variable is-1 is-multiline is-mobile is-size-7-mobile">
        <span class="column is-narrow">
            
                <span>4月 29 2021</span>
            
        </span>
        
        <span class="column is-narrow article-category">
            <i class="far fa-folder"></i>
            <a class="article-category-link" href="/zh-cn/categories/Study/">Study</a><span>></span><a class="article-category-link" href="/zh-cn/categories/Study/Java/">Java</a>
        </span>
        
        
        <span class="column is-narrow">
            
            
            35 分钟 读完 (约 5306 字)
        </span>
        
    </div>
    <div class="article-entry is-size-6-mobile" itemprop="articleBody">
    
        <html><head></head><body><p>什么是反射？反射就是Reflection，Java的反射是指程序在运行期可以拿到一个对象的所有信息。反射是为了解决在运行期，对某个实例一无所知的情况下，如何调用其方法。<span id="more"></span>正常情况下，如果我们要调用一个对象的方法，或者访问一个对象的字段，通常会传入对象实例。</p>
<h2 id="Class类"><a href="#Class类" class="headerlink" title="Class类"></a>Class类</h2><p>除了int等基本类型外，Java的其他类型全部都是class（包括interface）。仔细思考我们可以得出结论：class的本质是数据类型（Type）。无继承关系的数据类型无法赋值：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java">Number n = <span class="hljs-keyword">new</span> Double(<span class="hljs-number">123.456</span>); <span class="hljs-comment">// OK</span><br>String s = <span class="hljs-keyword">new</span> Double(<span class="hljs-number">123.456</span>); <span class="hljs-comment">// compile error!</span><br></code></pre></td></tr></tbody></table></figure>

<p>而class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时，将其加载到内存。每加载一种class，JVM就为其创建一个<code>Class</code>类型的实例，并关联起来。注意，这里的Class类型是一个名叫Class的class。它长这样：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Class</span></span>{<br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">Class</span><span class="hljs-params">()</span></span>{};<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>以String类为例，当JVM加载String类时，它首先读取String.class类到内存，然后为String类创建一个Class实例并关联起来。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">Class cls = <span class="hljs-keyword">new</span> Class(String);<br></code></pre></td></tr></tbody></table></figure>

<p>这个Class实例是JVM内部创建的，如果我们查看JDK源码，可以发现Class类的构造方法是private，只有JVM能创建Class实例，我们自己的Java程序是无法创建Class实例的。</p>
<p>所以，JVM持有的每个Class实例都指向一个数据类型（class或interface）。一个Class实例包含了该class的所有信息。</p>
<figure class="highlight plaintext hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">┌───────────────────────────┐<br>│      Class Instance       │──────&gt; String<br>├───────────────────────────┤<br>│name = "java.lang.String"  │<br>└───────────────────────────┘<br>┌───────────────────────────┐<br>│      Class Instance       │──────&gt; Random<br>├───────────────────────────┤<br>│name = "java.util.Random"  │<br>└───────────────────────────┘<br>┌───────────────────────────┐<br>│      Class Instance       │──────&gt; Runnable<br>├───────────────────────────┤<br>│name = "java.lang.Runnable"│<br>└───────────────────────────┘<br><br>┌───────────────────────────┐<br>│      Class Instance       │──────&gt; String<br>├───────────────────────────┤<br>│name = "java.lang.String"  │<br>├───────────────────────────┤<br>│package = "java.lang"      │<br>├───────────────────────────┤<br>│super = "java.lang.Object" │<br>├───────────────────────────┤<br>│interface = CharSequence...│<br>├───────────────────────────┤<br>│field = value[],hash,...   │<br>├───────────────────────────┤<br>│method = indexOf()...      │<br>└───────────────────────────┘<br></code></pre></td></tr></tbody></table></figure>

<p>由于JVM为每个加载的class创建了对应的Class实例，并在实例中保存了该class的所有信息，包括类名、包名、父类、实现的接口、所有方法、字段等，因此，如果获取了某个Class实例，我们就可以通过这个Class实例获取到对应的class的所有信息。</p>
<p>这种通过Class实例获取class信息的方法称为反射（Reflection）。</p>
<p>如何获取一个class的Class实例？有三个方法：</p>
<p>方法一：直接通过一个class的静态变量class获取</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">Class cls = String.class;<br></code></pre></td></tr></tbody></table></figure>

<p>方法二：如果我们有一个实例变量，可以通过该实例变量提供的<code>getClass()</code>方法获取。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java">String s = <span class="hljs-string">"Hello"</span>;<br>Class cls = s.getClass();<br></code></pre></td></tr></tbody></table></figure>

<p>方法三：如果知道一个class的完整类名，可以通过<code>Class.forName()</code>获取。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">Class cls = Class.forName(<span class="hljs-string">"java.lang.String"</span>);<br></code></pre></td></tr></tbody></table></figure>

<p>因为Class实例在JVM中是唯一的，所以上述方法获取的Class实例是同一个实例。</p>
<p>注意一下Class实例比较和instanceof的差别。用instanceof不但匹配指定的类型，还匹配指定的子类。而用==判断class实例可以精确地判断数据类型，但不能作为子类型比较。</p>
<p>通常情况下，我们应该用instanceof判断数据类型，因为面向抽象编程的时候，我们不关心具体的子类型。只有在需要精确判断一个类型是不是某个class时，我们才使用==判断class实例。</p>
<p>因为反射的目的是为了获取某个实例的信息。因此，当我们拿到某个Object实例时，我们可以通过反射获取该Object的class信息。</p>
<p>注意到数组也是一种Class，例如String[]，而且不同于String.class，它的类名是<code>[Ljava.lang.String</code>。此外，JVM为每一种基本类型如int也创建了Class，通过int.class访问。</p>
<p>如果获取到一个Class实例，我们就可以通过该Class实例来创建对应类型的实例：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 获取String的Class实例:</span><br>Class cls = String.class;<br><span class="hljs-comment">// 创建一个String实例:</span><br>String s = (String) cls.newInstance();<br></code></pre></td></tr></tbody></table></figure>

<p>上述代码相当于<code>new String()</code>。通过<code>Class.newInstance()</code>可以创建类实例，它的局限是：只能调用<code>public</code>的无参数构造方法。带参数的构造方法，或者非<code>public</code>的构造方法都无法通过<code>Class.newInstance()</code>被调用。</p>
<h3 id="动态加载"><a href="#动态加载" class="headerlink" title="动态加载"></a>动态加载</h3><p>JVM在执行Java程序时，并不是一次性把所有用到的class全部加载到内存，而是第一次需要用到class时才加载。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// Main.java</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{<br>        <span class="hljs-keyword">if</span> (args.length &gt; <span class="hljs-number">0</span>) {<br>            create(args[<span class="hljs-number">0</span>]);<br>        }<br>    }<br>    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">create</span><span class="hljs-params">(String name)</span> </span>{<br>        Person p = <span class="hljs-keyword">new</span> Person(name);<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>当执行<code>Main.java</code>时，由于用到了<code>Main</code>，因此，JVM首先会把<code>Main.class</code>加载到内存。然而，并不会加载<code>Person.class</code>，除非程序执行到<code>create()</code>方法，JVM发现需要加载<code>Person</code>类时，才会首次加载<code>Person.class</code>。如果没有执行<code>create()</code>方法，那么<code>Person.class</code>根本就不会被加载。</p>
<p>这就是JVM动态加载class的特性。</p>
<p>动态加载class的特性对于Java程序非常重要。利用JVM动态加载class的特性，我们才能在运行期根据条件加载不同的实现类。例如，Commons Logging总是优先使用Log4j，只有当Log4j不存在时，才使用JDK的logging。利用JVM的动态加载特性，大致的实现代码如下：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// Commons Logging优先使用Log4j:</span><br>LogFactory factory = <span class="hljs-keyword">null</span>;<br><span class="hljs-keyword">if</span> (isClassPresent(<span class="hljs-string">"org.apache.logging.log4j.Logger"</span>)) {<br>    factory = createLog4j();<br>} <span class="hljs-keyword">else</span> {<br>    factory = createJdkLog();<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">isClassPresent</span><span class="hljs-params">(String name)</span> </span>{<br>    <span class="hljs-keyword">try</span> {<br>        Class.forName(name);<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br>    } <span class="hljs-keyword">catch</span> (Exception e) {<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>这就是为什么我们只需要把Log4j的jar包放到classpath中，Commons Logging就会自动使用Log4j的原因。</p>
<h2 id="访问字段"><a href="#访问字段" class="headerlink" title="访问字段"></a>访问字段</h2><p>我们先看看如何通过Class实例获取字段信息。Class类提供了以下几个方法来获取字段：</p>
<ul>
<li>Field getField(name)：根据字段名获取某个public的field（包括父类）</li>
<li>Field getDeclaredField(name)：根据字段名获取当前类的某个field（不包括父类）</li>
<li>Field[] getFields()：获取所有public的field（包括父类）</li>
<li>Field[] getDeclaredFields()：获取当前类的所有field（不包括父类）</li>
</ul>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Class stdClass = Student.class;<br>        <span class="hljs-comment">// 获取public字段"score":</span><br>        System.out.println(stdClass.getField(<span class="hljs-string">"score"</span>));<br>        <span class="hljs-comment">// 获取继承的public字段"name":</span><br>        System.out.println(stdClass.getField(<span class="hljs-string">"name"</span>));<br>        <span class="hljs-comment">// 获取private字段"grade":</span><br>        System.out.println(stdClass.getDeclaredField(<span class="hljs-string">"grade"</span>));<br>    }<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Person</span> </span>{<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> score;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> grade;<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{<br>    <span class="hljs-keyword">public</span> String name;<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>上述代码首先获取获取Student的Class实例，然后分别获取public字段、继承的public字段以及private字段，打印出的Field类似：</p>
<figure class="highlight plaintext hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">public int Student.score<br>public java.lang.String Person.name<br>private int Student.grade<br></code></pre></td></tr></tbody></table></figure>

<p>一个Field对象包含了一个字段的所有信息。</p>
<ul>
<li>getName()，返回字段名称，例如，“name”</li>
<li>getType()，返回字段类型，也是一个Class实例，例如，String.class</li>
<li>getModifiers()，返回字段的修饰符，它是一个int，不同的bit代表不同的含义</li>
</ul>
<p>以String类的value字段为例，我们用反射获取该字段的信息，代码如下：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">String</span> </span>{<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">byte</span>[] value;<br>}<br><br>Field f = String.class.getDeclaredField(<span class="hljs-string">"value"</span>);<br>f.getName(); <span class="hljs-comment">// "value"</span><br>f.getType(); <span class="hljs-comment">// class [B 表示byte[]类型</span><br><span class="hljs-keyword">int</span> m = f.getModifiers();<br>Modifier.isFinal(m); <span class="hljs-comment">// true</span><br>Modifier.isPublic(m); <span class="hljs-comment">// false</span><br>Modifier.isProtected(m); <span class="hljs-comment">// false</span><br>Modifier.isPrivate(m); <span class="hljs-comment">// true</span><br>Modifier.isStatic(m); <span class="hljs-comment">// false</span><br></code></pre></td></tr></tbody></table></figure>

<h3 id="获取字段值"><a href="#获取字段值" class="headerlink" title="获取字段值"></a>获取字段值</h3><p>利用反射拿到字段的一个Field实例，我们还可以拿到一个实例对应的该字段的值。</p>
<p>例如，对于一个Person实例，我们可以先拿到name字段对应的Field，再获取这个实例的name字段的值。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Object p = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Xiao Ming"</span>);<br>        Class c = p.getClass();<br>        Field f = c.getDeclaredField(<span class="hljs-string">"name"</span>);<br>        Object value = f.get(p);<br>        System.out.println(value); <span class="hljs-comment">// "Xiao Ming"</span><br>    }<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span><span class="hljs-params">(String name)</span> </span>{<br>        <span class="hljs-keyword">this</span>.name = name;<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>上述代码先获取Class实例，再获取Field实例，然后用<code>Field.get(Object)</code>获取指定实例的指定字段值。运行代码，如果不出意外，会得到一个<code>IllegalAccessException</code>，这是因为name被定义为一个private字段，正常情况下，Main类无法访问Person类的private字段。要修复错误，可以将private改为public，或者，在调用<code>Object value = f.get(p);</code>前，先写一句：<code>f.setAccessible(true);</code>。调用Field.setAccessible(true)的意思是，别管这个字段是不是public，一律允许访问。</p>
<p>有同学会问：如果使用反射可以获取private字段的值，那么类的封装还有什么意义？</p>
<p>答案是正常情况下，我们总是通过p.name来访问Person的name字段，编译器会根据public、protected和private决定是否允许访问字段，这样就达到了数据封装的目的。</p>
<p>而反射是一种非常规的用法，使用反射，首先代码非常繁琐，其次，它更多地是给工具或底层框架来使用，目的是在不知道目标实例任何信息的情况下，获取特定字段的值。此外，<code>setAccessible(true)</code>可能会失败。如果JVM运行期存在<code>SecurityManager</code>，那么它会根据规则进行检查，有可能阻止setAccessible(true)。例如，某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true)，这样可以保证JVM核心库的安全。</p>
<h3 id="设置字段值"><a href="#设置字段值" class="headerlink" title="设置字段值"></a>设置字段值</h3><p>通过Field实例既然可以获取到指定实例的字段值，自然也可以设置字段的值。设置字段值是通过<code>Field.set(Object, Object)</code>实现的，第一个Object参数是指定的实例，第二个Object参数是待修改的值。</p>
<p>同样的，修改非public字段，需要首先调用setAccessible(true)。</p>
<h2 id="调用方法"><a href="#调用方法" class="headerlink" title="调用方法"></a>调用方法</h2><p>我们已经通过Class实例获取所有Field对象，同样的，可以通过Class实例获取所有的Method信息。Class类提供了以下几个方法来获取Method：</p>
<ul>
<li>Method getMethod(name, Class…)：获取某个public的Method（包括父类）</li>
<li>Method getDeclaredMethod(name, Class…)：获取当前类的某个Method（不包括父类）</li>
<li>Method[] getMethods()：获取所有public的Method（包括父类）</li>
<li>Method[] getDeclaredMethods()：获取当前类的所有Method（不包括父类）</li>
</ul>
<p>我们来看一下实例代码：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Class stdClass = Student.class;<br>        <span class="hljs-comment">// 获取public方法getScore，参数为String:</span><br>        System.out.println(stdClass.getMethod(<span class="hljs-string">"getScore"</span>, String.class));<br>        <span class="hljs-comment">// 获取继承的public方法getName，无参数:</span><br>        System.out.println(stdClass.getMethod(<span class="hljs-string">"getName"</span>));<br>        <span class="hljs-comment">// 获取private方法getGrade，参数为int:</span><br>        System.out.println(stdClass.getDeclaredMethod(<span class="hljs-string">"getGrade"</span>, <span class="hljs-keyword">int</span>.class));<br>    }<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Person</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getScore</span><span class="hljs-params">(String type)</span> </span>{<br>        <span class="hljs-keyword">return</span> <span class="hljs-number">99</span>;<br>    }<br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getGrade</span><span class="hljs-params">(<span class="hljs-keyword">int</span> year)</span> </span>{<br>        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;<br>    }<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>{<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">"Person"</span>;<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>上述代码首先获取Student的Class实例，然后分别获取public方法、继承的public方法以及private方法，打印出来的Method类似：</p>
<figure class="highlight plaintext hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs plaintext">public int Student.getScore(java.lang.String)<br>public java.lang.String Person.getName()<br>private int Student.getGrade(int)<br></code></pre></td></tr></tbody></table></figure>

<p>一个Method对象包含一个方法的所有信息：</p>
<ul>
<li>getName()：返回方法名称，例如：”getScore”；</li>
<li>getReturnType()：返回方法返回值类型，也是一个Class实例，例如：String.class；</li>
<li>getParameterTypes()：返回方法的参数类型，是一个Class数组，例如：{String.class, int.class}；</li>
<li>getModifiers()：返回方法的修饰符，它是一个int，不同的bit表示不同的含义。</li>
</ul>
<h3 id="调用方法-1"><a href="#调用方法-1" class="headerlink" title="调用方法"></a>调用方法</h3><p>当我们获取到一个Method对象时，就可以对它进行调用。以下面的代码为例：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java">String s = <span class="hljs-string">"Hello world"</span>;<br>String r = s.substring(<span class="hljs-number">6</span>); <span class="hljs-comment">// "world"</span><br></code></pre></td></tr></tbody></table></figure>

<p>如果用反射来调用substring方法，需要以下代码：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        <span class="hljs-comment">// String对象:</span><br>        String s = <span class="hljs-string">"Hello world"</span>;<br>        <span class="hljs-comment">// 获取String substring(int)方法，参数为int:</span><br>        Method m = String.class.getMethod(<span class="hljs-string">"substring"</span>, <span class="hljs-keyword">int</span>.class);<br>        <span class="hljs-comment">// 在s对象上调用该方法并获取结果:</span><br>        String r = (String) m.invoke(s, <span class="hljs-number">6</span>);<br>        <span class="hljs-comment">// 打印调用结果:</span><br>        System.out.println(r);<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>对Method实例调用<code>invoke</code>就相当于调用该方法，invoke的第一个参数是对象实例，即在哪个实例上调用该方法，后面的可变参数要与方法参数一致，否则将报错。</p>
<h3 id="调用静态方法"><a href="#调用静态方法" class="headerlink" title="调用静态方法"></a>调用静态方法</h3><p>如果获取到的Method表示一个静态方法，调用静态方法时，由于无需指定实例对象，所以invoke方法传入的第一个参数永远为null。我们以<code>Integer.parseInt(String)</code>为例：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        <span class="hljs-comment">// 获取Integer.parseInt(String)方法，参数为String:</span><br>        Method m = Integer.class.getMethod(<span class="hljs-string">"parseInt"</span>, String.class);<br>        <span class="hljs-comment">// 调用该静态方法并获取结果:</span><br>        Integer n = (Integer) m.invoke(<span class="hljs-keyword">null</span>, <span class="hljs-string">"12345"</span>);<br>        <span class="hljs-comment">// 打印调用结果:</span><br>        System.out.println(n);<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<h3 id="调用非public方法"><a href="#调用非public方法" class="headerlink" title="调用非public方法"></a>调用非public方法</h3><p>和Field类似，对于非public方法，我们虽然可以通过Class.getDeclaredMethod()获取该方法实例，但直接对其调用将得到一个IllegalAccessException。为了调用非public方法，我们通过Method.setAccessible(true)允许其调用：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Person p = <span class="hljs-keyword">new</span> Person();<br>        Method m = p.getClass().getDeclaredMethod(<span class="hljs-string">"setName"</span>, String.class);<br>        m.setAccessible(<span class="hljs-keyword">true</span>);<br>        m.invoke(p, <span class="hljs-string">"Bob"</span>);<br>        System.out.println(p.name);<br>    }<br>}<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{<br>    String name;<br>    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>{<br>        <span class="hljs-keyword">this</span>.name = name;<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>此外，setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager，那么它会根据规则进行检查，有可能阻止setAccessible(true)。例如，某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true)，这样可以保证JVM核心库的安全。</p>
<h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>我们来考察这样一种情况：一个Person类定义了hello()方法，并且它的子类Student也覆写了hello()方法，那么从Person.class获取的Method，作用于Student实例时，调用方法到底是哪个？测试一下发现，使用反射调用方法时，仍然遵循多态原则：即总是调用实际类型的覆写方法。</p>
<h2 id="调用构造方法"><a href="#调用构造方法" class="headerlink" title="调用构造方法"></a>调用构造方法</h2><p>我们通常使用new操作符创建新的实例。如果通过反射来创建新的实例，可以调用Class提供的newInstance()方法。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">Person p = Person.class.newInstance();<br></code></pre></td></tr></tbody></table></figure>

<p>调用Class.newInstance()的局限是，它只能调用该类的public无参数构造方法。如果构造方法带有参数，或者不是public，就无法直接通过Class.newInstance()来调用。</p>
<p>为了调用任意的构造方法，Java的反射API提供了Constructor对象，它包含一个构造方法的所有信息，可以创建一个实例。Constructor对象和Method对象非常像，不同之处仅在于它是一个构造方法，并且调用结果总是返回实例。</p>
<p>通过Class实例获取Constructor的方法如下：</p>
<ul>
<li>getConstructor(Class…)：获取某个public的Constructor；</li>
<li>getDeclaredConstructor(Class…)：获取某个Constructor；</li>
<li>getConstructors()：获取所有public的Constructor；</li>
<li>getDeclaredConstructors()：获取所有Constructor。</li>
</ul>
<p>注意，Constructor总是当前类定义的构造方法，和父类无关，因此不存在多态的问题。</p>
<p>调用非public的Constructor时，必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。</p>
<h2 id="获取继承关系"><a href="#获取继承关系" class="headerlink" title="获取继承关系"></a>获取继承关系</h2><p>获取父类的class。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Class i = Integer.class;<br>        Class n = i.getSuperclass();<br>        System.out.println(n);<br>        Class o = n.getSuperclass();<br>        System.out.println(o);<br>        System.out.println(o.getSuperclass());<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>运行上述代码，可以看到，Integer的父类类型是Number，Number的父类是Object，Object的父类是null。除Object外，其他任何非interface的Class都必定存在一个父类类型。</p>
<h3 id="获取interface"><a href="#获取interface" class="headerlink" title="获取interface"></a>获取interface</h3><p>由于一个类可能实现一个或多个接口，通过Class我们就可以查询到实现的接口类型。例如，查询Integer实现的接口：</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br>        Class s = Integer.class;<br>        Class[] is = s.getInterfaces();<br>        <span class="hljs-keyword">for</span> (Class i : is) {<br>            System.out.println(i);<br>        }<br>    }<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>注意，getInterfaces()只返回当前类直接实现的接口类型，并不包括其父类实现的接口类型。</p>
<p>此外，对所有interface的Class调用getSuperclass()返回的是null，获取接口的父接口要用getInterfaces()。如果一个类没有实现任何interface，那么getInterfaces()返回空数组。</p>
<h3 id="继承关系"><a href="#继承关系" class="headerlink" title="继承关系"></a>继承关系</h3><p>当我们判断一个实例是否是某个类型时，正常情况下使用instanceof操作符。如果是两个Class实例，要判断一个向上转型是否成立，可以调用isAssignableFrom()。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// Integer i = ?</span><br>Integer.class.isAssignableFrom(Integer.class); <span class="hljs-comment">// true，因为Integer可以赋值给Integer</span><br><span class="hljs-comment">// Number n = ?</span><br>Number.class.isAssignableFrom(Integer.class); <span class="hljs-comment">// true，因为Integer可以赋值给Number</span><br><span class="hljs-comment">// Object o = ?</span><br>Object.class.isAssignableFrom(Integer.class); <span class="hljs-comment">// true，因为Integer可以赋值给Object</span><br><span class="hljs-comment">// Integer i = ?</span><br>Integer.class.isAssignableFrom(Number.class); <span class="hljs-comment">// false，因为Number不能赋值给Integer</span><br></code></pre></td></tr></tbody></table></figure>

<h3 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h3><p>我们先定义了接口Hello，但是我们并不去编写实现类，而是直接通过JDK提供的一个Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式，我们称为动态代码。JDK提供的动态创建接口对象的方式，就叫动态代理。</p>
<figure class="highlight java hljs"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{<br>        InvocationHandler handler = <span class="hljs-keyword">new</span> InvocationHandler() {<br>            <span class="hljs-meta">@Override</span><br>            <span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">invoke</span><span class="hljs-params">(Object proxy, Method method, Object[] args)</span> <span class="hljs-keyword">throws</span> Throwable </span>{<br>                System.out.println(method);<br>                <span class="hljs-keyword">if</span> (method.getName().equals(<span class="hljs-string">"morning"</span>)) {<br>                    System.out.println(<span class="hljs-string">"Good morning, "</span> + args[<span class="hljs-number">0</span>]);<br>                }<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br>            }<br>        };<br>        Hello hello = (Hello) Proxy.newProxyInstance(<br>            Hello.class.getClassLoader(), <span class="hljs-comment">// 传入ClassLoader</span><br>            <span class="hljs-keyword">new</span> Class[] { Hello.class }, <span class="hljs-comment">// 传入要实现的接口</span><br>            handler); <span class="hljs-comment">// 传入处理调用方法的InvocationHandler</span><br>        hello.morning(<span class="hljs-string">"Bob"</span>);<br>    }<br>}<br><br><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Hello</span> </span>{<br>    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">morning</span><span class="hljs-params">(String name)</span></span>;<br>}<br></code></pre></td></tr></tbody></table></figure>

<p>在运行期动态创建一个<code>interface</code>实例的方法如下：</p>
<ol>
<li>定义一个<code>InvocationHandler</code>实例，它负责实现接口的方法调用；</li>
<li>通过Proxy.newProxyInstance()创建interface实例，它需要3个参数：<ol>
<li>使用的<code>ClassLoader</code>，通常就是接口类的<code>ClassLoader</code>；</li>
<li>需要实现的接口数组，至少需要传入一个接口进去；</li>
<li>用来处理接口方法调用的<code>InvocationHandler</code>实例。</li>
</ol>
</li>
<li>将返回的<code>Object</code>强制转型为接口。</li>
</ol>
<p>动态代理实际上是JVM在运行期动态创建class字节码并加载的过程。</p>
<p>这一节看的有点模棱两可，后面这篇文章讲的比较清楚，但也就不再总结这篇文章的大意了，需要的时候再拿过来翻翻看<a target="_blank" rel="noopener" href="https://www.jianshu.com/p/95970b089360">https://www.jianshu.com/p/95970b089360</a>。</p>
</body></html>
    
    </div>
    
    
    <div class="columns is-mobile is-multiline article-nav">
        <span class="column is-12-mobile is-half-desktop  article-nav-prev">
            
            <a href="/Study/Java/zh-cn/%E6%B3%A8%E8%A7%A3/">注解</a>
            
        </span>
        <span class="column is-12-mobile is-half-desktop  article-nav-next">
            
            <a href="/Study/Java/zh-cn/%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/">异常处理</a>
            
        </span>
    </div>
    
</article>


<div class="sharebox">
    
<div class="sharethis-inline-share-buttons"></div>
<script type='text/javascript' src='//platform-api.sharethis.com/js/sharethis.js#property=608c1408daac690012507aa2&amp;product=sop' async='async'></script>

</div>



    </div>
</section>
    <footer class="footer">
    <div class="container">
        <div class="columns content">
            <div class="column is-narrow has-text-centered">
                &copy; 2021 wanzixin&nbsp;
                Powered by <a href="http://hexo.io/" target="_blank">Hexo</a> & <a
                        target="_blank" rel="noopener" href="http://github.com/ppoffice/hexo-theme-minos">Minos</a>
            </div>
            <div class="column is-hidden-mobile"></div>

            
            <div class="column is-narrow">
                <div class="columns is-mobile is-multiline is-centered">
                
                    
                <a class="column is-narrow has-text-black" title="GitHub" target="_blank" rel="noopener" href="https://github.com/ppoffice/hexo-theme-minos">
                    
                    GitHub
                    
                </a>
                
                </div>
            </div>
            
            
<div class="column is-narrow has-text-centered">
    <div class="dropdown is-up is-right is-hoverable" style="margin-top: -0.2em;">
        <div class="dropdown-trigger">
            <button class="button is-small" aria-haspopup="true" aria-controls="dropdown-menu7">
                <span class="icon">
                    <i class="fas fa-globe"></i>
                </span>
                <span>简体中文</span>
                <span class="icon is-small">
            <i class="fas fa-angle-down" aria-hidden="true"></i>
          </span>
            </button>
        </div>
        <div class="dropdown-menu has-text-left" role="menu">
            <div class="dropdown-content">
            
                <a href="/Study/Java/zh-cn/%E5%8F%8D%E5%B0%84/" class="dropdown-item">
                    English
                </a>
            
                <a href="/zh-cn/Study/Java/zh-cn/%E5%8F%8D%E5%B0%84/" class="dropdown-item">
                    简体中文
                </a>
            
            </div>
        </div>
    </div>
</div>

        </div>
    </div>
</footer>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment-with-locales.min.js"></script>

<!-- test if the browser is outdated -->
<div id="outdated">
    <h6>Your browser is out-of-date!</h6>
    <p>Update your browser to view this website correctly. <a id="btnUpdateBrowser" target="_blank" rel="noopener" href="http://outdatedbrowser.com/">Update my browser now </a></p>
    <p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js"></script>
<script>
    $(document).ready(function () {
        // plugin function, place inside DOM ready function
        outdatedBrowser({
            bgColor: '#f25648',
            color: '#ffffff',
            lowerThan: 'flex'
        })
    });
</script>

<script>
    window.FontAwesomeConfig = {
        searchPseudoElements: true
    }
    moment.locale("zh-CN");
</script>


    
    
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML"></script>
<script>
    MathJax.Hub.Config({
        "HTML-CSS": {
            matchFontHeight: false
        },
        SVG: {
            matchFontHeight: false
        },
        CommonHTML: {
            matchFontHeight: false
        },
        tex2jax: {
            inlineMath: [
                ['$','$'],
                ['\\(','\\)']
            ]
        }
    });
</script>

    
    
    
    
<script src="//cdnjs.cloudflare.com/ajax/libs/lightgallery/1.6.8/js/lightgallery-all.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/justifiedGallery/3.6.5/js/jquery.justifiedGallery.min.js"></script>
<script>
    (function ($) {
        $(document).ready(function () {
            if (typeof($.fn.lightGallery) === 'function') {
                $('.article.gallery').lightGallery({ selector: '.gallery-item' });
            }
            if (typeof($.fn.justifiedGallery) === 'function') {
                $('.justified-gallery').justifiedGallery();
            }
        });
    })(jQuery);
</script>

    
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script>
    <style>
        .hljs {
            position: relative;
        }

        .hljs .clipboard-btn {
            float: right;
            color: #9a9a9a;
            background: none;
            border: none;
            cursor: pointer;
        }

        .hljs .clipboard-btn:hover {
          color: #8a8a8a;
        }

        .hljs > .clipboard-btn {
            display: none;
            position: absolute;
            right: 4px;
            top: 4px;
        }

        .hljs:hover > .clipboard-btn {
            display: inline;
        }

        .hljs > figcaption > .clipboard-btn {
            margin-right: 4px;
        }
    </style>
    <script>
      $(document).ready(function () {
        $('figure.hljs').each(function(i, figure) {
          var codeId = 'code-' + i;
          var code = figure.querySelector('.code');
          var copyButton = $('<button>Copy <i class="far fa-clipboard"></i></button>');
          code.id = codeId;
          copyButton.addClass('clipboard-btn');
          copyButton.attr('data-clipboard-target-id', codeId);

          var figcaption = figure.querySelector('figcaption');

          if (figcaption) {
            figcaption.append(copyButton[0]);
          } else {
            figure.prepend(copyButton[0]);
          }
        })

        var clipboard = new ClipboardJS('.clipboard-btn', {
          target: function(trigger) {
            return document.getElementById(trigger.getAttribute('data-clipboard-target-id'));
          }
        });
        clipboard.on('success', function(e) {
          e.clearSelection();
        })
      })
    </script>

    
    

    



<script src="/js/script.js"></script>


    
    <div class="searchbox ins-search">
    <div class="searchbox-mask"></div>
    <div class="searchbox-container ins-search-container">
        <div class="searchbox-input-wrapper">
            <input type="text" class="searchbox-input ins-search-input" placeholder="站内搜索" />
            <span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="searchbox-result-wrapper ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: '文章',
                PAGES: '页面',
                CATEGORIES: '分类',
                TAGS: '标签',
                UNTITLED: '(无标题)',
            },
            CONTENT_URL: '/content.zh-cn.json',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>

<script src="/js/insight.js"></script>

    
</body>
</html>